package com.think.grpcclient

import com.think.protocol.*
import com.think.protocol.FileInfo
import io.grpc.ManagedChannelBuilder
import io.grpc.StatusRuntimeException
import io.grpc.stub.StreamObserver
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import java.net.URL

/**
    这个项目可以运行，并且相互发送消息正常
https://www.cnblogs.com/kingsleylam/p/17069320.html  需要安装相关的windows环境（软件已经下载好了）
https://blog.csdn.net/haohulala/article/details/129211997 环境和文件目录（参照查看文件目录）
win+R  打开regedit  一定要采用  ;cmd.exe;powershell.exe;git.exe;*.exe;   必须有*.exe

    api 'com.google.code.gson:gson:2.9.0'
    api 'io.grpc:grpc-okhttp:1.47.0' // CURRENT_GRPC_VERSION
    api 'io.grpc:grpc-protobuf-lite:1.47.0' // CURRENT_GRPC_VERSION
    api 'io.grpc:grpc-stub:1.47.0' // CURRENT_GRPC_VERSION
    api 'org.apache.tomcat:annotations-api:6.0.53'
    api 'io.grpc:grpc-netty-shaded:1.47.0'

*/

object Client {
    private lateinit var blockingStub: GreeterGrpc.GreeterBlockingStub
    private lateinit var mSerStub: MserviceGrpc.MserviceStub

    lateinit var callResponse: CallResponse

    fun init(callResponse: CallResponse) {
        this.callResponse = callResponse
//        val str = "http://192.168.0.195:5001/"
        val str = "http://localhost:5001/"
        val url = URL(str)
        val port = if (url.port == -1) url.defaultPort else url.port

        LogUtil.d("Connecting to ${url.host}:$port")
        callResponse.onBlock("Connecting to ${url.host}:$port")
        val builder = ManagedChannelBuilder.forAddress(url.host, port)
        if (url.protocol == "https") {
            builder.useTransportSecurity()
        } else {
            builder.usePlaintext()
        }

        val channel = builder.executor(Dispatchers.Default.asExecutor()).build()
        blockingStub = GreeterGrpc.newBlockingStub(channel)
        mSerStub = MserviceGrpc.newStub(channel)
    }

    fun sayHello(name: String) {
        if (!::callResponse.isInitialized) {
            throw RuntimeException("NO INIT")
        }
        callResponse.onBlock("Will try to sayHello $name")

        LogUtil.d("Will try to greet $name")
        val request = HelloRequest.newBuilder().setName(name).build()
        var response: HelloReply
        try {
            response = blockingStub.sayHello(request)
        } catch (e: StatusRuntimeException) {
            callResponse.onBlock(" error: {${e.status.cause?.message}}")
            LogUtil.d(" error: {${e.status.cause?.message}}")
            return
        }

        callResponse.onBlock("response:${response.message}")
    }


    fun getSerTime() {
        if (!::callResponse.isInitialized) {
            throw RuntimeException("NO INIT")
        }
        callResponse.onBlock("Will try to getSerTime")

        LogUtil.d("Will try to getSerTime")
        val request = Empty.newBuilder().build()
        try {
            mSerStub.getSerTime(request, object : StreamObserver<StrReply> {
                override fun onNext(value: StrReply?) {
                    callResponse.onBlock("getSerTime_onNext:${value?.message}")

                }

                override fun onError(t: Throwable?) {
                    callResponse.onBlock("getSerTime_onError:${t?.message}")

                }

                override fun onCompleted() {
                    callResponse.onBlock("getSerTime_onCompleted")
                }

            })
        } catch (e: StatusRuntimeException) {
            callResponse.onBlock(" error: {${e.status.cause?.message}}")
            LogUtil.d(" error: {${e.status.cause?.message}}")
            return
        }

    }

    fun getSerStreamTime() {
        if (!::callResponse.isInitialized) {
            throw RuntimeException("NO INIT")
        }
        callResponse.onBlock("Will try to getSerStreamTime")

        LogUtil.d("Will try to getSerStreamTime")
        val request = Empty.newBuilder().build()
        try {
            mSerStub.getSerStreamTime(request, object : StreamObserver<StrReply> {
                override fun onNext(value: StrReply?) {
                    callResponse.onBlock("getSerStreamTime_onNext" + value?.message)
                }

                override fun onError(t: Throwable?) {
                    callResponse.onBlock("getSerStreamTime_onError" + t?.message)
                }

                override fun onCompleted() {
                    callResponse.onBlock("getSerStreamTime_onCompleted")
                }

            })

        } catch (e: StatusRuntimeException) {
            callResponse.onBlock(" error: {${e.status.cause?.message}}")
            LogUtil.d(" error: {${e.status.cause?.message}}")
            return
        }


    }


    fun uploadFileStream() {
        if (!::callResponse.isInitialized) {
            throw RuntimeException("NO INIT")
        }
        callResponse.onBlock("Will try to uploadFileStream")

        LogUtil.d("Will try to uploadFileStream")
        try {

            val request = mSerStub.uploadFileStream(object : StreamObserver<FileNameList> {
                override fun onError(t: Throwable?) {
                    callResponse.onBlock("uploadFileStream_onError" + t?.message)
                }

                override fun onCompleted() {
                    callResponse.onBlock("uploadFileStream_onCompleted")
                }

                override fun onNext(value: FileNameList?) {

                    val mList = value?.strOrBuilderList
                    callResponse.onBlock("uploadFileStream_onNext--${mList?.size}")

                    mList?.forEachIndexed { index, strReplyOrBuilder ->
                        callResponse.onBlock("uploadFileStream_onNext--${index}" + strReplyOrBuilder.message)
                    }

                }
            })

           Thread {
               for (i in 1..30) {
                   Thread.sleep(500)
                   val reply: FileInfo = FileInfo.newBuilder().setFileName("客户端上传i=${i}文件").build()
                   request.onNext(reply)
               }
               request.onCompleted()
           }.start()

        } catch (e: StatusRuntimeException) {
            callResponse.onBlock(" error: {${e.status.cause?.message}}")
            LogUtil.d(" error: {${e.status.cause?.message}}")
            return
        }


    }


    fun downloadStream() {
        if (!::callResponse.isInitialized) {
            throw RuntimeException("NO INIT")
        }
        callResponse.onBlock("Will try to downloadStream")

        LogUtil.d("Will try to downloadStream")
        try {

            val request = mSerStub.downloadStream(object : StreamObserver<FileInfo> {
                override fun onError(t: Throwable?) {
                    callResponse.onBlock("downloadStream_onError" + t?.message)
                }

                override fun onCompleted() {
                    callResponse.onBlock("downloadStream_onCompleted")
                }

                override fun onNext(value: FileInfo) {
                    callResponse.onBlock("downloadStream_onNext--${value?.fileName}")
                }
            })

            Thread {
                for (i in 1..30) {
                    Thread.sleep(500)
                    val reply: FilePath = FilePath.newBuilder().setPath("客户端下载-i=${i}文件").build()
                    request.onNext(reply)
                }
                request.onCompleted()
            }.start()
        } catch (e: StatusRuntimeException) {
            callResponse.onBlock(" error: {${e.status.cause?.message}}")
            LogUtil.d(" error: {${e.status.cause?.message}}")
            return
        }


    }
}

